home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLE / EX_ANGLE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  19.2 KB  |  520 lines

  1.  
  2. /*
  3.  * MODULE NAME: ex_angle.c
  4.  *
  5.  * FUNCTION: 
  6.  * This module contains code that draws extrusions with angled
  7.  * joins ("angle join style").  It also inserts colors and normals 
  8.  * where necessary, if appropriate.
  9.  *
  10.  * HISTORY:
  11.  * written by Linas Vepstas August/September 1991
  12.  * split into multiple compile units, Linas, October 1991
  13.  * added normal vectors Linas, October 1991
  14.  * "code complete" (that is, I'm done), Linas Vepstas, October 1991
  15.  * work around OpenGL's lack of support for concave polys, June 1994
  16.  */
  17.  
  18. #include <stdlib.h>
  19. #include <math.h>
  20. #include <string.h>    /* for the memcpy() subroutine */
  21. #include <GL/tube.h>
  22. #include "port.h"
  23. #include "gutil.h"
  24. #include "vvector.h"
  25. #include "tube_gc.h"
  26. #include "extrude.h"
  27. #include "intersect.h"
  28. #include "segment.h"
  29.  
  30. /* ============================================================ */
  31. /*
  32.  * Algorithmic trivia:
  33.  * 
  34.  * There is a slight bit of trivia which the super-duper exacto coder
  35.  * needs to know about the code in this module. It is this:
  36.  *
  37.  * This module attempts to correctly treat contour normal vectors 
  38.  * by applying the inverse transpose of the 2D contour affine
  39.  * transformation to the 2D contour normals.  This is perfectly correct,
  40.  * when applied to the "raw" join style.  However, if the affine transform
  41.  * has a strong rotational component, AND the join style is angle or
  42.  * cut, then the normal vectors would continue to rotate as the
  43.  * intersect point is extrapolated. 
  44.  * 
  45.  * The extrapolation of the inverse-transpose matrix to the intersection
  46.  * point is not done.  This would appear to be overkill for most
  47.  * situations.  The viewer might possibly detect an artifact of the 
  48.  * failure to do this correction IF all three of the following criteria 
  49.  * were met:
  50.  * 1) The affine xform has a strong rotational component,
  51.  * 2) The angle between two succesive segments is sharp (greater than 15 or
  52.  *    30 degrees).
  53.  * 3) The join style is angle or cut.
  54.  *
  55.  * However, I beleive that it is highly unlikely that the viewer will
  56.  * detect any artifacts. The reason I beleive this is that a strong
  57.  * rotational component will twist a segment so strongly that the more
  58.  * visible artifact will be that a segment is composed of triangle strips.
  59.  * As the user attempts to minimize the tesselation artifacts by shortening
  60.  * segments, then the rotational component will decrease in proportion,
  61.  * and the lighting artifact will fall away.
  62.  *
  63.  * To summarize, there is a slight inexactness in this code.  The author
  64.  * of the code beleives that this inexactness results in miniscule
  65.  * errors in every situation.
  66.  *
  67.  * Linas Vepstas March 1993
  68.  */
  69.  
  70. /* ============================================================ */
  71.  
  72. void draw_angle_style_front_cap (int ncp,    /* number of contour points */
  73.                            gleDouble bi[3],        /* biscetor */
  74.                            gleDouble point_array[][3])    /* polyline */
  75. {
  76.    int j;
  77. #ifdef OPENGL_10
  78.    GLUtriangulatorObj *tobj;
  79. #endif /* OPENGL_10 */
  80.  
  81.    if (bi[2] < 0.0) {
  82.       VEC_SCALE (bi, -1.0, bi); 
  83.    }
  84.  
  85. #ifdef GL_32
  86.    /* old-style gl handles concave polygons no problem, so the code is
  87.     * simple.  New-style gl is a lot more tricky. */
  88.    /* draw the end cap */
  89.    BGNPOLYGON ();
  90.  
  91.    N3F (bi);
  92.    for (j=0; j<ncp; j++) {
  93.       V3F (point_array[j], j, FRONT_CAP);
  94.    }
  95.    ENDPOLYGON ();
  96. #endif /* GL_32 */
  97.  
  98. #ifdef OPENGL_10
  99.    N3F(bi);
  100.  
  101.    tobj = gluNewTess ();
  102.    gluTessCallback (tobj, GLU_BEGIN, glBegin);
  103.    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
  104.    gluTessCallback (tobj, GLU_END, glEnd);
  105.    gluBeginPolygon (tobj);
  106.  
  107.    for (j=0; j<ncp; j++) {
  108.       gluTessVertex (tobj, point_array[j], point_array[j]);
  109.    }
  110.    gluEndPolygon (tobj);
  111.    gluDeleteTess (tobj);
  112. #endif /* OPENGL_10 */
  113. }
  114.  
  115. /* ============================================================ */
  116.  
  117. void draw_angle_style_back_cap (int ncp,    /* number of contour points */
  118.                            gleDouble bi[3],        /* biscetor */
  119.                            gleDouble point_array[][3])    /* polyline */
  120. {
  121.    int j;
  122. #ifdef OPENGL_10
  123.    GLUtriangulatorObj *tobj;
  124. #endif /* OPENGL_10 */
  125.  
  126.    if (bi[2] > 0.0) {
  127.       VEC_SCALE (bi, -1.0, bi); 
  128.    }
  129.  
  130. #ifdef GL_32
  131.    /* old-style gl handles concave polygons no problem, so the code is
  132.     * simple.  New-style gl is a lot more tricky. */
  133.    /* draw the end cap */
  134.    BGNPOLYGON ();
  135.  
  136.    N3F (bi);
  137.    for (j=ncp-1; j>=0; j--) {
  138.       V3F (point_array[j], j, BACK_CAP);
  139.    }
  140.    ENDPOLYGON ();
  141. #endif /* GL_32 */
  142.  
  143. #ifdef OPENGL_10
  144.    N3F (bi);
  145.  
  146.    tobj = gluNewTess ();
  147.    gluTessCallback (tobj, GLU_BEGIN, glBegin);
  148.    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
  149.    gluTessCallback (tobj, GLU_END, glEnd);
  150.    gluBeginPolygon (tobj);
  151.  
  152.    for (j=ncp-1; j>=0; j--) {
  153.       gluTessVertex (tobj, point_array[j], point_array[j]);
  154.    }
  155.    gluEndPolygon (tobj);
  156.    gluDeleteTess (tobj);
  157. #endif /* OPENGL_10 */
  158. }
  159.  
  160. /* ============================================================ */
  161.  
  162. void extrusion_angle_join (int ncp,        /* number of contour points */
  163.                            gleDouble contour[][2],    /* 2D contour */
  164.                            gleDouble cont_normal[][2], /* 2D normal vecs */
  165.                            gleDouble up[3],    /* up vector for contour */
  166.                            int npoints,        /* numpoints in poly-line */
  167.                            gleDouble point_array[][3],    /* polyline */
  168.                            float color_array[][3],    /* color of polyline */
  169.                            gleDouble xform_array[][2][3])  /* 2D contour xforms */
  170. {
  171.    int i, j;
  172.    int inext, inextnext;
  173.    gleDouble m[4][4];
  174.    gleDouble len;
  175.    gleDouble len_seg;
  176.    gleDouble diff[3];
  177.    gleDouble bi_0[3], bi_1[3];        /* bisecting plane */
  178.    gleDouble bisector_0[3], bisector_1[3];    /* bisecting plane */
  179.    gleDouble end_point_0[3], end_point_1[3]; 
  180.    gleDouble origin[3], neg_z[3];
  181.    gleDouble yup[3];        /* alternate up vector */
  182.    gleDouble *front_loop, *back_loop;   /* contours in 3D */
  183.    char * mem_anchor;
  184.    double *norm_loop; 
  185.    double *front_norm, *back_norm, *tmp; /* contour normals in 3D */
  186.    int first_time;
  187.  
  188.    /* By definition, the contour passed in has its up vector pointing in
  189.     * the y direction */
  190.    if (up == NULL) {
  191.       yup[0] = 0.0;
  192.       yup[1] = 1.0;
  193.       yup[2] = 0.0;
  194.    } else {
  195.       VEC_COPY(yup, up);
  196.    }
  197.  
  198.    /* ========== "up" vector sanity check ========== */
  199.    (void) up_sanity_check (yup, npoints, point_array);
  200.  
  201.    /* the origin is at the origin */
  202.    origin [0] = 0.0;
  203.    origin [1] = 0.0;
  204.    origin [2] = 0.0;
  205.  
  206.    /* and neg_z is at neg z */
  207.    neg_z[0] = 0.0;
  208.    neg_z[1] = 0.0;
  209.    neg_z[2] = 1.0;
  210.  
  211.    /* ignore all segments of zero length */
  212.    i = 1;
  213.    inext = i;
  214.    FIND_NON_DEGENERATE_POINT (inext, npoints, len, diff, point_array);
  215.    len_seg = len;    /* store for later use */
  216.  
  217.    /* get the bisecting plane */
  218.    bisecting_plane (bi_0, point_array[0], 
  219.                           point_array[1], 
  220.                           point_array[inext]);
  221.    /* reflect the up vector in the bisecting plane */
  222.    VEC_REFLECT (yup, yup, bi_0);
  223.  
  224.    /* malloc the storage we'll need for relaying changed contours to the
  225.     * drawing routines. */
  226.    mem_anchor =  malloc (2 * 3 * ncp * sizeof(double)
  227.                       +  2 * 3 * ncp * sizeof(gleDouble));
  228.    front_loop = (gleDouble *) mem_anchor;
  229.    back_loop = front_loop + 3 * ncp;
  230.    front_norm = (double *) (back_loop + 3 * ncp);
  231.    back_norm = front_norm + 3 * ncp;
  232.    norm_loop = front_norm;
  233.  
  234.    /* may as well get the normals set up now */
  235.    if (cont_normal != NULL) {
  236.       if (xform_array == NULL) {
  237.          for (j=0; j<ncp; j++) {
  238.             norm_loop[3*j] = cont_normal[j][0];
  239.             norm_loop[3*j+1] = cont_normal[j][1];
  240.             norm_loop[3*j+2] = 0.0;
  241.          }
  242.       } else {
  243.          for (j=0; j<ncp; j++) {
  244.             NORM_XFORM_2X2 ( (&front_norm[3*j]),
  245.                               xform_array[inext-1],
  246.                               cont_normal [j]);
  247.             front_norm[3*j+2] = 0.0;
  248.             back_norm[3*j+2] = 0.0;
  249.          }
  250.       }
  251.    }
  252.  
  253.    first_time = TRUE;
  254.    /* draw tubing, not doing the first segment */
  255.    while (inext<npoints-1) {
  256.  
  257.       inextnext = inext;
  258.       /* ignore all segments of zero length */
  259.       FIND_NON_DEGENERATE_POINT (inextnext, npoints, len, diff, point_array);
  260.  
  261.       /* get the next bisecting plane */
  262.       bisecting_plane (bi_1, point_array[i], 
  263.                              point_array[inext], 
  264.                              point_array[inextnext]);  
  265.  
  266.       /* rotate so that z-axis points down v2-v1 axis, 
  267.        * and so that origen is at v1 */
  268.       uviewpoint (m, point_array[i], point_array[inext], yup);
  269.       PUSHMATRIX ();
  270.       MULTMATRIX (m);
  271.  
  272.       /* rotate the bisecting planes into the local coordinate system */
  273.       MAT_DOT_VEC_3X3 (bisector_0, m, bi_0);
  274.       MAT_DOT_VEC_3X3 (bisector_1, m, bi_1);
  275.  
  276.       neg_z[2] = -len_seg;
  277.  
  278.       /* draw the tube */
  279.       /* --------- START OF TMESH GENERATION -------------- */
  280.       for (j=0; j<ncp; j++) {
  281.  
  282.          /* if there are normals, and there are either affine xforms, OR
  283.           * path-edge normals need to be drawn, then compute local
  284.           * coordinate system normals. 
  285.           */
  286.          if (cont_normal != NULL) {
  287.           
  288.             /* set up the back normals. (The front normals we inherit
  289.              * from previous pass through the loop) */
  290.             if (xform_array != NULL) {
  291.                /* do up the normal vectors with the inverse transpose */
  292.                NORM_XFORM_2X2 ( (&back_norm[3*j]),
  293.                                  xform_array[inext],
  294.                                  cont_normal [j]);
  295.             }
  296.  
  297.             /* Note that if the xform array is NULL, then normals are
  298.              * constant, and are set up outside of the loop.
  299.              */
  300.  
  301.             /* 
  302.              * if there are normal vectors, and the style calls for it, 
  303.              * then we want to project the normal vectors into the
  304.              * bisecting plane. (This style is needed to make toroids, etc. 
  305.              * look good: Without this, segmentation artifacts show up
  306.              * under lighting.
  307.              */
  308.             if (__TUBE_DRAW_PATH_EDGE_NORMALS) {
  309.                /* Hmm, if no affine xforms, then we haven't yet set
  310.                 * back vector. So do it. */
  311.                if (xform_array == NULL) {
  312.                   back_norm[3*j] = cont_normal[j][0];
  313.                   back_norm[3*j+1] = cont_normal[j][1];
  314.                }
  315.    
  316.                /* now, start with a fresh normal (z component equal to
  317.                 * zero), project onto bisecting plane (by computing 
  318.                 * perpendicular componenet to bisect vector, and renormalize 
  319.                 * (since projected vector is not of unit length */ 
  320.                front_norm[3*j+2] = 0.0;
  321.                VEC_PERP ((&front_norm[3*j]), (&front_norm[3*j]), bisector_0);
  322.                VEC_NORMALIZE ((&front_norm[3*j]));
  323.     
  324.                back_norm[3*j+2] = 0.0;
  325.                VEC_PERP ((&back_norm[3*j]), (&back_norm[3*j]), bisector_1);
  326.                VEC_NORMALIZE ((&back_norm[3*j]));
  327.             } 
  328.          } 
  329.  
  330.          /* Next, we want to define segements. We find the endpoints of
  331.           * the segments by intersecting the contour with the bisecting
  332.           * plane.  If there is no local affine transform, this is easy.
  333.           *
  334.           * If there is an affine tranform, then we want to remove the
  335.           * torsional component, so that the intersection points won't
  336.           * get twisted out of shape.  We do this by applying the
  337.           * local affine transform to the entire coordinate system.
  338.           */
  339.          if (xform_array == NULL) {
  340.             end_point_0 [0] = contour[j][0];
  341.             end_point_0 [1] = contour[j][1];
  342.    
  343.             end_point_1 [0] = contour[j][0];
  344.             end_point_1 [1] = contour[j][1];
  345.          } else {
  346.             /* transform the contour points with the local xform */
  347.             MAT_DOT_VEC_2X3 (end_point_0,
  348.                              xform_array[inext-1], contour[j]);
  349.             MAT_DOT_VEC_2X3 (end_point_1,
  350.                              xform_array[inext-1], contour[j]);
  351.          }
  352.  
  353.          end_point_0 [2] = 0.0;
  354.          end_point_1 [2] = - len_seg;
  355.  
  356.          /* The two end-points define a line.  Intersect this line
  357.           * against the clipping plane defined by the PREVIOUS
  358.           * tube segment.  */
  359.  
  360.          INNERSECT ((&front_loop[3*j]), /* intersection point (returned) */
  361.                     origin,        /* point on intersecting plane */
  362.                     bisector_0,        /* normal vector to plane */
  363.                     end_point_0,    /* point on line */
  364.                     end_point_1);    /* another point on the line */    
  365.  
  366.          /* The two end-points define a line.  Intersect this line
  367.           * against the clipping plane defined by the NEXT
  368.           * tube segment.  */
  369.  
  370.          /* if there's an affine coordinate change, be sure to use it */
  371.          if (xform_array != NULL) {
  372.             /* transform the contour points with the local xform */
  373.             MAT_DOT_VEC_2X3 (end_point_0,
  374.                              xform_array[inext], contour[j]);
  375.             MAT_DOT_VEC_2X3 (end_point_1,
  376.                              xform_array[inext], contour[j]);
  377.          }
  378.  
  379.          INNERSECT ((&back_loop[3*j]),    /* intersection point (returned) */
  380.                     neg_z,        /* point on intersecting plane */
  381.                     bisector_1,        /* normal vector to plane */
  382.                     end_point_0,    /* point on line */
  383.                     end_point_1);    /* another point on the line */    
  384.  
  385.       }
  386.  
  387.       /* --------- END OF TMESH GENERATION -------------- */
  388.  
  389.       /* v^v^v^v^v^v^v^v^v  BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  390.  
  391.       /* if end caps are required, draw them. But don't draw any 
  392.        * but the very first and last caps */
  393.       if (__TUBE_DRAW_CAP) {
  394.          if (first_time) {
  395.             if (color_array != NULL) C3F (color_array[inext-1]);
  396.             first_time = FALSE;
  397.             draw_angle_style_front_cap (ncp, bisector_0, (gleVector *) front_loop);
  398.          }
  399.          if (inext == npoints-2) {
  400.             if (color_array != NULL) C3F (color_array[inext]);
  401.             draw_angle_style_back_cap (ncp, bisector_1, (gleVector *) back_loop);
  402.          }
  403.       }
  404.       /* v^v^v^v^v^v^v^v^v  END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
  405.  
  406.       /* |||||||||||||||||| START SEGMENT DRAW |||||||||||||||||||| */
  407.       /* There are six different cases we can have for presence and/or
  408.        * absecnce of colors and normals, and for interpretation of
  409.        * normals. The blechy set of nested if statements below
  410.        * branch to each of the six cases */
  411.       if ((xform_array == NULL) && (!__TUBE_DRAW_PATH_EDGE_NORMALS)) {
  412.          if (color_array == NULL) {
  413.             if (cont_normal == NULL) {
  414.                draw_segment_plain (ncp, (gleVector *) front_loop,
  415.                                         (gleVector *) back_loop, inext, len_seg);
  416.             } else
  417.             if (__TUBE_DRAW_FACET_NORMALS) {
  418.                draw_segment_facet_n (ncp, (gleVector *) front_loop,
  419.                                           (gleVector *) back_loop, 
  420.                                           (gleVector *) norm_loop, inext, len_seg);
  421.             } else {
  422.                draw_segment_edge_n (ncp, (gleVector *) front_loop, 
  423.                                          (gleVector *) back_loop, 
  424.                                          (gleVector *) norm_loop, inext, len_seg);
  425.             }
  426.          } else {
  427.             if (cont_normal == NULL) {
  428.                draw_segment_color (ncp, (gleVector *) front_loop, 
  429.                                         (gleVector *) back_loop, 
  430.                                    color_array[inext-1],
  431.                                    color_array[inext], inext, len_seg);
  432.             } else
  433.             if (__TUBE_DRAW_FACET_NORMALS) {
  434.                draw_segment_c_and_facet_n (ncp, 
  435.                                    (gleVector *) front_loop, 
  436.                                    (gleVector *) back_loop, 
  437.                                    (gleVector *) norm_loop,
  438.                                    color_array[inext-1],
  439.                                    color_array[inext], inext, len_seg);
  440.             } else {
  441.                draw_segment_c_and_edge_n (ncp, 
  442.                                    (gleVector *) front_loop, 
  443.                                    (gleVector *) back_loop, 
  444.                                    (gleVector *) norm_loop,
  445.                                    color_array[inext-1],
  446.                                    color_array[inext], inext, len_seg);
  447.              }
  448.           }
  449.       } else {
  450.          if (color_array == NULL) {
  451.             if (cont_normal == NULL) {
  452.                draw_segment_plain (ncp, (gleVector *) front_loop, 
  453.                                         (gleVector *)  back_loop, inext, len_seg);
  454.             } else 
  455.             if (__TUBE_DRAW_FACET_NORMALS) {
  456.                draw_binorm_segment_facet_n (ncp, (gleVector *) front_loop, 
  457.                                                  (gleVector *) back_loop,
  458.                                                  (gleVector *) front_norm, 
  459.                                                  (gleVector *) back_norm,
  460.                                                  inext, len_seg);
  461.             } else {
  462.                draw_binorm_segment_edge_n (ncp, (gleVector *) front_loop, 
  463.                                                 (gleVector *) back_loop,
  464.                                                 (gleVector *) front_norm,
  465.                                                 (gleVector *) back_norm,
  466.                                                 inext, len_seg);
  467.             }
  468.          } else {
  469.             if (cont_normal == NULL) {
  470.                draw_segment_color (ncp, (gleVector *) front_loop, 
  471.                                         (gleVector *) back_loop, 
  472.                                    color_array[inext-1],
  473.                                    color_array[inext], inext, len_seg);
  474.             } else
  475.             if (__TUBE_DRAW_FACET_NORMALS) {
  476.                draw_binorm_segment_c_and_facet_n (ncp, 
  477.                                    (gleVector *) front_loop, 
  478.                                    (gleVector *) back_loop, 
  479.                                    (gleVector *) front_norm, 
  480.                                    (gleVector *) back_norm, 
  481.                                    color_array[inext-1],
  482.                                    color_array[inext], inext, len_seg);
  483.             } else {
  484.                draw_binorm_segment_c_and_edge_n (ncp, 
  485.                                    (gleVector *) front_loop, 
  486.                                    (gleVector *) back_loop, 
  487.                                    (gleVector *) front_norm, 
  488.                                    (gleVector *) back_norm, 
  489.                                    color_array[inext-1],
  490.                                    color_array[inext], inext, len_seg);
  491.              }
  492.           }
  493.       }
  494.       /* |||||||||||||||||| END SEGMENT DRAW |||||||||||||||||||| */
  495.  
  496.       /* pop this matrix, do the next set */
  497.       POPMATRIX ();
  498.  
  499.       /* bump everything to the next vertex */
  500.       len_seg = len;
  501.       i = inext;
  502.       inext = inextnext;
  503.       VEC_COPY (bi_0, bi_1);
  504.  
  505.       /* trade norm loops */
  506.       tmp = front_norm;
  507.       front_norm = back_norm;
  508.       back_norm = tmp;
  509.  
  510.       /* reflect the up vector in the bisecting plane */
  511.       VEC_REFLECT (yup, yup, bi_0);
  512.    }
  513.  
  514.    /* be sure to free it all up */
  515.    free (mem_anchor);
  516.  
  517. }
  518.    
  519. /* ============================================================ */
  520.